using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Collections;
using System.Linq;
using Riantsoft.P2pServer.Models;
using Riantsoft.P2pServer.Controllers;
using System.Configuration;
using Riantsoft.Common;

namespace Riantsoft.P2pServer.View
{
    public partial class ServerMainForm : Form
    {
        //Server server = new Server();
        //List<ShowDevice> Devices = new List<ShowDevice>();
        private UdpClient listener;
        //private UdpClient transitUdp;
        //private Thread serverThread;
        private IPEndPoint remotePoint;
        private List<int> _ports;
        private IPEndPoint transitServerIpe;
        private string queryText;
        private bool cmdConnectTest;
        private P2pController control;
        private Dictionary<string, string> logs;
        private static long logsIndex = 0;

        public List<int> Ports
        {
            get { return _ports; }
            set { _ports = value; }
        }

        public ServerMainForm()
        {
            InitializeComponent();

            _ports = new List<int>();
            remotePoint = new IPEndPoint(IPAddress.Any, 0);
            udpPortNumericUpDown.Value = Utils.P2pServerDefaultPort;
            transitPortNumericUpDown.Value = Convert.ToInt32(ConfigurationManager.AppSettings["P2pTransitServerPort"]);
            transitServerIpTextBox.Text = ConfigurationManager.AppSettings["P2pTransitServerIpAddress"];

            this.Text += string.Format("  v{0}", AssemblyVersion);
            logs = new Dictionary<string, string>();
        }

        private string _DeviceOffPushUrl;

        public string DeviceOffPushUrl
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_DeviceOffPushUrl))
                    _DeviceOffPushUrl = System.Configuration.ConfigurationManager.AppSettings["DeviceOffPushUrl"];
                return _DeviceOffPushUrl;
            }
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            StartProcess();
        }

        public void StartProcess()
        {
            //Device device = new Device();
            startButton.Enabled = false;
            stopButton.Enabled = true;
            startToolStripStatusLabel.Text = string.Format("Start at {0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Ports.Add((int)udpPortNumericUpDown.Value);

            try
            {
                //if (control == null)
                //{
                    control = new P2pController();
                //}
                transitServerIpe = new IPEndPoint(IPAddress.Parse(transitServerIpTextBox.Text.Trim()), (int)transitPortNumericUpDown.Value);
                control.TransitServerIpe = transitServerIpe;
                control.DeviceOffPushUrl = DeviceOffPushUrl;
                control.StartPushDeviceOffMessage(3 * 60);
                control.StartSaveDeviceRecords(5);

                //using (var db = new DAL.P2pServerContext())
                //{
                //    DeviceList = db.Devices.ToList();
                //}

                listener = new UdpClient(Ports[0]);
                //transitUdp = new UdpClient((int)transitPortNumericUpDown.Value);

                //serverThread.Start();
                serverBackgroundWorker.RunWorkerAsync(listener);
                //transitServerBackgroundWorker.RunWorkerAsync(transitUdp);
                //Console.WriteLine("P2P Server started, waiting client connect...");
                string msg = string.Format("P2P Server started, found {0} devies in DB.", control.DeviceList.Count);
                SysUtils.WriteLog(msg);
                AddRowToLogView(0, msg);
            }
            catch (Exception exp)
            {
                //Console.WriteLine("Start P2P Server error: " + exp.Message);
                SysUtils.WriteLog(exp.Message + System.Environment.NewLine + exp.StackTrace);
                AddRowToLogView(0, "Start P2P Server error: " + exp.Message);
                throw exp;
            }
        }

        private void ServerMainForm_Load(object sender, EventArgs e)
        {
            statusLabel.Text = string.Empty;
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            serverBackgroundWorker.CancelAsync();
            serverBackgroundWorker.Dispose();
            //transitServerBackgroundWorker.CancelAsync();
            //transitServerBackgroundWorker.Dispose();

            listener.Close();

            control.StopPushDeviceOffMessage();
            control.StopSaveDeviceRecords();
            control.SaveChanges();
            //transitUdp.Close();
            //deviceListTimer.Enabled = false;
            //deviceListTimer.Stop();
            //server.Stop();

            startButton.Enabled = true;
            stopButton.Enabled = false;
        }
        
        private void serverBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            UdpClient udp = (UdpClient)e.Argument;
            byte[] buffer = new byte[1024];
            IPEndPoint remoteIpe = new IPEndPoint(IPAddress.Any, 0);

            BackgroundWorker worker = sender as BackgroundWorker;

            while (true)
            {
                control.Process(udp, remoteIpe, buffer, worker);
                if (worker.CancellationPending)
                    break;
            }
        }

        public static string AssemblyVersion
        {
            get
            {
                return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
            }
        }

        private void serverBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            AddRowToLogView(e.ProgressPercentage, e.UserState);
        }

        private void serverBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //serverBackgroundWorker.RunWorkerAsync(listener);
        }

        void AddRowToLogView(int state, object value)
        {
            //if (mdoLogDataGridView.Rows.Count >= 1000)
            //    mdoLogDataGridView.Rows.Clear();

            //int rowIndex = mdoLogDataGridView.Rows.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff"), value);

            //mdoLogDataGridView.Rows[rowIndex + 1].Cells[0].Selected = true;

            if (logs.Count >= 10000)
                logs.Clear();
            if (logsIndex > 100000)
                logsIndex = 0;

            logs.Add(string.Format("{0}_{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff"), logsIndex++), value.ToString());

            string queryText = p2pCodeTextBox.Text.Trim();
            string contain = value.ToString();

            if (string.IsNullOrWhiteSpace(queryText) == false && contain.Contains(queryText))
            {
                if (queryResultDataGridView.Rows.Count >= 1000)
                    queryResultDataGridView.Rows.Clear();

                int rowIndex = queryResultDataGridView.Rows.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff"), value);

                queryResultDataGridView.Rows[rowIndex + 1].Cells[0].Selected = true;
            }
        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            //mdoLogDataGridView.Rows.Clear();

            logs.Clear();
        }

        private void transitServerBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
        }


        private void transitServerBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            AddRowToLogView(e.ProgressPercentage, e.UserState);
        }

        private void transitServerBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
        }

        private void queryButton_Click(object sender, EventArgs e)
        {
            queryResultDataGridView.Rows.Clear();
            //p2pCodeTextBox.Text = p2pCodeTextBox.Text.ToUpper();
            queryText = p2pCodeTextBox.Text.ToUpper();

            //foreach (DataGridViewRow item in mdoLogDataGridView.Rows)
            //{
            //    if (item.Cells.Count > 1 && item.Cells[1].Value != null)
            //    {
            //        string contain = item.Cells[1].Value.ToString();
            //        if (contain.Contains(p2pCodeTextBox.Text))
            //            queryResultDataGridView.Rows.Add(item.Cells[0].Value, item.Cells[1].Value);
            //    }
            //}
            foreach (var item in logs)
            {
                    if (item.Value.Contains(p2pCodeTextBox.Text))
                        queryResultDataGridView.Rows.Add(item.Key, item.Value);
            }
        }

        private void statusButton_Click(object sender, EventArgs e)
        {
            BackgroundWorker statusBackgroundWorker = new BackgroundWorker();
            statusBackgroundWorker.DoWork += new DoWorkEventHandler(statusBackgroundWorker_DoWork);
            statusBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(statusBackgroundWorker_RunWorkerCompleted);

            if (statusBackgroundWorker.IsBusy == false)
                statusBackgroundWorker.RunWorkerAsync();
        }

        void statusBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            statusLabel.Text = (string)e.Result;
        }

        void statusBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            int totalDevice = control.DeviceList.Count;
            int onlineDevice = 0;
            int totalTransitDevice = control.TransitList.Count;

            int count = 0;
            DateTime now = DateTime.Now;
            foreach (var item in control.DeviceList)
            {
                if ((now - item.LastUpdatedDate).TotalMinutes < 30)
                    count++;
            }
            onlineDevice = count;

            count = 0;
            foreach (var item in control.TransitList)
            {
                if ((now - item.LastUpdatedDate).TotalMinutes < 30)
                    count++;
            }
            totalTransitDevice = count;

            string status = string.Format("Devices:{0}, online:{1}, transit:{2}, R:{3}, RR:{4}, TR:{5} at {6}", totalDevice, onlineDevice, totalTransitDevice, 
                control.Status.ConnectRequest, control.Status.ReceiveConnectRequest, control.Status.TransitConnectRequest, now.ToLongTimeString());
            e.Result = status;
        }

        private void cmdConnectTestCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            cmdConnectTest = cmdConnectTestCheckBox.Checked;
        }
    }
}
